// 为什么运算符重载通常设置为友元函数而非成员函数
// 运算符重载可以实现为成员函数或友元函数，选择哪种方式取决于具体情况。让我解释两种方式的区别和各自的优缺点：

// 成员函数 vs 友元函数的关键区别
// 当运算符重载作为成员函数时：
// 左操作数必须是类的对象
// 运算符函数有一个隐含的this参数，指向左操作数
// 只能访问类的私有和保护成员

// 当运算符重载作为友元函数时：
// 左右操作数都作为显式参数传递
// 没有隐含的this参数
// 可以访问类的私有和保护成员（因为是友元）

// 为什么经常使用友元函数
// 1.对称性和转换支持
// 最重要的原因是支持隐式类型转换。考虑这个例子：
class String
{
public:
    // 成员函数版本
    String operator+(const String &rhs) const;
};

String s1, s2;
String s3 = s1 + s2;      // 有效：s1.operator+(s2)
String s4 = s1 + "hello"; // 有效：s1.operator+(String("hello"))
String s5 = "hello" + s1; // 无效！"hello"不是String对象，无法调用成员函数

// 如果使用友元函数：
class String
{
public:
    // 构造函数允许从const char*隐式转换
    String(const char *s);

    // 友元函数版本
    friend String operator+(const String &lhs, const String &rhs);
};

String s1, s2;
String s3 = s1 + s2;      // 有效：operator+(s1, s2)
String s4 = s1 + "hello"; // 有效：operator+(s1, String("hello"))
String s5 = "hello" + s1; // 有效！operator+(String("hello"), s1)

// 友元函数允许任一操作数进行隐式转换，而成员函数只允许右操作数转换。

// 2.语义清晰性
// 友元函数使得二元运算符的两个操作数在代码中显得更加对称，更符合直觉：
// 友元函数版本 - 两个参数对称
friend bool operator==(const Complex &lhs, const Complex &rhs);

// 成员函数版本 - 不对称，一个是this，一个是参数
bool operator==(const Complex &rhs) const;

// 3.与标准库一致性
// 标准库中的许多运算符重载都是作为非成员函数实现的，使用友元函数与标准库风格保持一致。

// 何时使用成员函数
// 并非所有运算符都适合作为友元函数。以下情况更适合使用成员函数：
// 1.赋值运算符 =、+=、-=等：这些运算符修改对象状态，自然应该是成员函数
// 2.下标运算符 []：需要访问容器内部结构
// 3.函数调用运算符 ()：通常实现函子
// 4.成员访问运算符 ->：用于智能指针等
// 5.自增/自减运算符 ++/--：修改对象状态

// 最佳实践
// 一个常见的经验法则是：
// 1.如果运算符修改对象状态（如=, +=, []），使用成员函数
// 2.如果运算符是对称的（如+, -, ==），使用友元函数